﻿using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using AutoPoco;
using AutoPoco.DataSources;
using AutoPoco.Engine;
using InvoiceProject.Controllers;
using InvoiceProject.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting.Web;
using InvoiceProject.Enums;
using Moq;
using NUnit.Framework;
using ExpectedException = Microsoft.VisualStudio.TestTools.UnitTesting.ExpectedExceptionAttribute;


namespace InvoiceProject.Tests.InvoicesUnitTests
{


    [TestClass()]
    public class AfterCalculatingInvoiceWithInvoiceItems
    {


        [TestMethod()]
        [Microsoft.VisualStudio.TestTools.UnitTesting.ExpectedException(typeof(ValidationException))]
        public void ShouldFailwhenInvoiceTotalIncTaxIsNotEqualZero()
        {

            var target = new Invoice();
            target.Business = ModelGenerator.GetTestBusiness();
            target.Customer = new Customer
                                  {
                                      BusinessId = 43,
                                      Email = "IF0045@Gmail.com,",
                                      FirstName = "FN",
                                      LastName = "LstName"
                                  };
            target.InvoiceDate = DateTime.Now;
            target.InvoiceItems = ModelGenerator.GetInvoiceItemList(7);
          //  target.UserCreated = "ME";
            target.UserModified = "ME";
           // target.DateCreated = DateTime.Now;
            target.DateModified = DateTime.Now;
            target.TotalIncTax = 54;
            target.TotalTax = 0;

            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext, true);
            //Get invoice object saving
            //                target.Validate(validationContext);


        }



        [TestMethod()]
        [ExpectedException(typeof(ValidationException))]
        public void ShouldFailwhenInvoiceTotalIncTaxIsGreaterThanZeroAndTotalTaxIsZero()
        {

            var target = new Invoice();
            target.Business = ModelGenerator.GetTestBusiness();
            target.Customer = new Customer
            {
                BusinessId = 43,
                Email = "IF0045@Gmail.com,",
                FirstName = "FN",
                LastName = "LstName"
            };
            target.InvoiceDate = DateTime.Now;
            target.InvoiceItems = ModelGenerator.GetInvoiceItemList(32);
      //      target.UserCreated = "ME";
            target.UserModified = "ME";
        //    target.DateCreated = DateTime.Now;
            target.DateModified = DateTime.Now;
            target.TotalIncTax = 532;
            target.TotalTax = 0;

            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext, true);

            target.TotalIncTax.ShouldNotEqual(0);


        }

        [TestMethod()]
        [ExpectedException(typeof(ValidationException))]
        public void ShouldFailWhenInvoiceItemsDoNotAddUpToTotalIncTaxAndTotalTax()
        {

            var target = new Invoice();
            target.Business = ModelGenerator.GetTestBusiness();
            target.Customer = new Customer
            {
                BusinessId = 43,
                Email = "IF0045@Gmail.com,",
                FirstName = "FN",
                LastName = "LstName"
            };
            target.InvoiceDate = DateTime.Now;
            target.InvoiceItems = ModelGenerator.GetInvoiceItemList(32);
           // target.UserCreated = "ME";
            target.UserModified = "ME";
           // target.DateCreated = DateTime.Now;
            target.DateModified = DateTime.Now;
            target.TotalIncTax = 432;
            target.TotalTax = 76554;
            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext);
            target.TotalTax.ShouldNotEqual(0);
        }





    }


    [TestClass()]
    public class CalculateInvoice
    {
        [TestMethod()]
        public void InvoiceItemTaxCalculation_ShouldPass_WhenValid()
        {
            Business business = ModelGenerator.GetTestBusiness();
            Invoice target = ModelGenerator.GetInvoice();


            target.InvoiceItems = new List<InvoiceItem>();
            target.InvoiceItems.Add(new InvoiceItem { Quantity = 10, Rate = 5 });
            target.InvoiceItems.Add(new InvoiceItem { Quantity = 30, Rate = 1.43M });


            decimal invoiceItem1ExpectedTax = (10 * 5) * business.LookupTaxCountry.TaxRate;
            decimal invoiceItem2ExpectedTax = 30 * 1.43M * business.LookupTaxCountry.TaxRate;

            //ACT
            target.Calculate();
            target.InvoiceItems[0].Tax.ShouldEqual(invoiceItem1ExpectedTax);
            target.InvoiceItems[1].Tax.ShouldEqual(invoiceItem2ExpectedTax);
            //ASSERT

            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext);

        }


        [TestMethod()]
        public void InvoiceItemSubTotalCalculation_ShouldPass_WhenValid()
        {
            Business business = ModelGenerator.GetTestBusiness();
            Invoice target = ModelGenerator.GetInvoice();


            target.InvoiceItems = new List<InvoiceItem>();
            target.InvoiceItems.Add(new InvoiceItem { Quantity = 10, Rate = 5 });
            target.InvoiceItems.Add(new InvoiceItem { Quantity = 30, Rate = 1.43M });


            decimal invoiceItem1ExpectedTax = (10 * 5) * business.LookupTaxCountry.TaxRate;
            decimal invoiceItem2ExpectedTax = 30 * 1.43M * business.LookupTaxCountry.TaxRate;

            decimal invoiceSubTotal1 = 10 * 5 + invoiceItem1ExpectedTax;

            decimal invoiceSubTotal2 = 30 * 1.43M + invoiceItem2ExpectedTax;

            //ACT
            target.Calculate();
            target.InvoiceItems[0].SubTotal.ShouldEqual(invoiceSubTotal1);
            target.InvoiceItems[1].SubTotal.ShouldEqual(invoiceSubTotal2);
            //ASSERT

            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext);

        }


       

        [TestMethod()]
        public void ShouldPassWhen_SumOfInvoiceItemTax_DoesEqual_InvoiceTotalTax()
        {
            //ARRANGE
            Business business = ModelGenerator.GetTestBusiness();
            Invoice target = ModelGenerator.GetInvoice();

            decimal expectedTotalTax = 0;

            foreach (var invoiceItem in target.InvoiceItems)
            {
                var total = invoiceItem.Quantity * invoiceItem.Rate;
                expectedTotalTax += total * business.LookupTaxCountry.TaxRate;
            }

            //ACT
            target.Calculate();

            //ASSERT
            target.TotalTax.ShouldEqual(expectedTotalTax);

            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext);

        }

        [TestMethod()]
        [ExpectedException(typeof(ValidationException))]
        public void ShouldFailWhen_SumOfInvoiceItemTax_DoesNotEqual_InvoiceTotalTax()
        {
            //ARRANGE
            Business business = ModelGenerator.GetTestBusiness();
            Invoice target = ModelGenerator.GetInvoice();

            decimal expectedTotalTax = 0;

            foreach (var invoiceItem in target.InvoiceItems)
            {
                var total = invoiceItem.Quantity * invoiceItem.Rate;
                expectedTotalTax += total * business.LookupTaxCountry.TaxRate;
            }

            //ACT
            target.Calculate();
            target.TotalTax += 432;
            //ASSERT

            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext);

        }

        [TestMethod()]
        [ExpectedException(typeof(ValidationException))]
        public void ShouldFailWhen_ItemIsAddedAfterCalculateAndTotalTaxDoesNotMatch()
        {
            //ARRANGE
            Business business = ModelGenerator.GetTestBusiness();
            Invoice target = ModelGenerator.GetInvoice();
            decimal expectedTotalTax = 0;


            //ACT
            target.Calculate();


            target.InvoiceItems.Add(new InvoiceItem { Quantity = 32, Rate = 44 });

            foreach (var invoiceItem in target.InvoiceItems)
            {
                var total = invoiceItem.Quantity * invoiceItem.Rate;
                expectedTotalTax += total * business.LookupTaxCountry.TaxRate;
            }

            //ASSERT

            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext);

        }

        [TestMethod()]
        [ExpectedException(typeof(ValidationException))]
        public void ShouldFailWhen_SumOfInvoiceItemsPlusTaxTotal_DoesNotEqual_InvoiceInclTax()
        {
            //ARRANGE
            Business business = ModelGenerator.GetTestBusiness();
            Invoice target = ModelGenerator.GetInvoice();

            //SET tax rate for testing
            business.LookupTaxCountry.TaxRate = .1M;

            decimal expectedTotalInclTax = target.InvoiceItems.Select(invoiceItem => invoiceItem.Quantity*invoiceItem.Rate).Select(total => total*business.LookupTaxCountry.TaxRate + total).Sum();

            //ACT
            target.Calculate();
            target.TotalIncTax += 15340;
            //ASSERT

            //Assert
            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext);
        }

        [TestMethod()]
        public void ShouldPassWhen_SumOfInvoiceItemsPlusTaxTotal_DoesEqual_InvoiceInclTax()
        {
            //ARRANGE
            Business business = ModelGenerator.GetTestBusiness();
            Invoice target = ModelGenerator.GetInvoice();

            //SET tax rate for testing
            business.LookupTaxCountry.TaxRate = .1M;

            decimal expectedTotalInclTax = 0;

            foreach (var invoiceItem in target.InvoiceItems)
            {
                var total = invoiceItem.Quantity * invoiceItem.Rate;
                expectedTotalInclTax += total * business.LookupTaxCountry.TaxRate + total;
            }

            //ACT
            target.Calculate();

            //ASSERT
            target.TotalIncTax.ShouldEqual(expectedTotalInclTax);

            //Assert
            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext);
        }


        [TestMethod()]
        [Microsoft.VisualStudio.TestTools.UnitTesting.ExpectedException(typeof(ValidationException))]
        public void ShouldFailWhen_ItemIsAddedAfterCalculateAndTotalInclTaxDoesNotMatch()
        {
            //ARRANGE
            Business business = ModelGenerator.GetTestBusiness();
            Invoice target = ModelGenerator.GetInvoice();
                decimal expectedTotalTax = 0;


            //ACT
            target.Calculate();


            target.InvoiceItems.Add(new InvoiceItem { Quantity = 32, Rate = 44 });


            target.TotalIncTax += 4322;
            //Assert
            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext);


        }

        [TestMethod()]
        [Microsoft.VisualStudio.TestTools.UnitTesting.ExpectedException(typeof(ValidationException))]
        public void ShouldFailWhen_ItemIsAddedAfterCalculateAndTotalDoesNotMatch()
        {
            //ARRANGE
            Business business = ModelGenerator.GetTestBusiness();
            Invoice target = ModelGenerator.GetInvoice();
                decimal expectedTotalTax = 0;


            //ACT
            target.Calculate();


            target.InvoiceItems.Add(new InvoiceItem { Quantity = 32, Rate = 44 });


          //  target.TotalTax += 4322;
            //Assert
            var validationContext = new ValidationContext(target, null, null);
            Validator.ValidateObject(target, validationContext);


        }



    }



}



